package com.flyqiu.flow.core.handler;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.flyqiu.common.bean.FlyQiuBeanManage;
import com.flyqiu.common.tools.StringTools;
import com.flyqiu.common.user.FlyQiuUser;
import com.flyqiu.common.user.FlyQiuUserTools;
import com.flyqiu.flow.api.context.FlyQiuFlowGlobalContext;
import com.flyqiu.flow.api.context.ProcInstContext;
import com.flyqiu.flow.bpmn.element.ProcessModel;
import com.flyqiu.flow.bpmn.element.StartEvent;
import com.flyqiu.flow.bpmn.element.SubProcessModel;
import com.flyqiu.flow.common.std.ActivityHandlerResult;
import com.flyqiu.flow.core.DefaultProcInstContext;
import com.flyqiu.flow.event.ProcInstEvent;
import com.flyqiu.flow.mapper.HiProcInstMapper;
import com.flyqiu.flow.mapper.RuProcInstMapper;
import com.flyqiu.flow.model.entity.base.ProcInst;
import com.flyqiu.flow.model.entity.hi.ProcHiInst;
import com.flyqiu.flow.model.entity.ru.ProcRuActivity;
import com.flyqiu.flow.model.entity.ru.ProcRuInst;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class SubProcessHandler extends BaseProcActElementHandler<SubProcessModel, ProcRuInst> {
    private RuProcInstMapper ruProcInstMapper;
    private HiProcInstMapper historyInstMapper;

    @Override
    protected void initBean(FlyQiuBeanManage procBeanManage) {
        ruProcInstMapper = procBeanManage.getMapper(RuProcInstMapper.class);
        historyInstMapper = procBeanManage.getMapper(HiProcInstMapper.class);
    }

    @Override
    protected ActivityHandlerResult<ProcRuInst> startElementInst(ProcRuInst currentProcInst, ProcRuActivity ruActivity) {
        ProcRuInst subProcInst = createSubProcInst(currentProcInst, ruActivity);
        transactionManage.apply(() -> {


            procEventManage.triggerCreateBeforeEvent(ProcInstEvent.class, subProcInst);
            ruProcInstMapper.insert(subProcInst);
            ProcHiInst procHiInst = ProcHiInst.create(subProcInst);
            historyInstMapper.insert(procHiInst);
            procEventManage.triggerCreateAfterEvent(ProcInstEvent.class, subProcInst);


        });
        ActivityHandlerResult<ProcRuInst> result = new ActivityHandlerResult<>("");
        result.setActTypeInstId(subProcInst.getId());
        result.setAutoNext(true);
        return result;
    }

    private ProcRuInst createSubProcInst(ProcRuInst currentProcInst, ProcRuActivity ruActivity) {
        ProcRuInst subProcInst = new ProcRuInst();
        subProcInst.setActId(ruActivity.getId());
        subProcInst.setStatus(currentProcInst.getStatus());
        subProcInst.setTenantId(currentProcInst.getTenantId());
        subProcInst.setParentId(currentProcInst.getId());
        subProcInst.setParentProcDefKey(currentProcInst.getProcDeployDefKey());
        subProcInst.setParentLevelDefKeys(getLevelKeys(currentProcInst));
        subProcInst.setProcInstName(currentElement.getDefName());
        subProcInst.setProcDeployDefKey(currentElement.getDefKey());
        subProcInst.setProcDeployDefId(currentProcInst.getProcDeployDefId());
        subProcInst.setStartUserKey(currentProcInst.getStartUserKey());
        subProcInst.setTenantId(currentProcInst.getTenantId());
        subProcInst.setStartUserId(currentProcInst.getStartUserId());
        subProcInst.setCreateTime(LocalDateTime.now());
        FlyQiuUser flyQiuFlowAuthentication = FlyQiuUserTools.getAuthentication();
        if (flyQiuFlowAuthentication != null) {
            subProcInst.setTenantId(flyQiuFlowAuthentication.getTenantId());
            subProcInst.setStartUserId(flyQiuFlowAuthentication.getId());
            subProcInst.setStartUserKey(flyQiuFlowAuthentication.getUserType());
            subProcInst.setStartUserNickName(flyQiuFlowAuthentication.getNickName());
            subProcInst.setStartUserAttr(flyQiuFlowAuthentication.getUserAttr());
            subProcInst.setStartUserUniqueKey(flyQiuFlowAuthentication.getUniqueKey());

        }
        return subProcInst;
    }


    private String getLevelKeys(ProcRuInst parentProcInst) {
        String levelKeys = parentProcInst.getParentLevelDefKeys() == null ? "" : parentProcInst.getParentLevelDefKeys();
        List<String> levelKeyList = Arrays.stream(levelKeys.split(",")).filter(StringTools::isNotEmpty).collect(Collectors.toList());
        levelKeyList.add(parentProcInst.getParentProcDefKey());
        return String.join(",", levelKeyList);
    }

    @Override
    protected void startNextActivity(ProcInstContext procContext, ProcRuActivity currentRuActivity) {
        LambdaQueryWrapper<ProcRuInst> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProcInst::getActId, currentRuActivity.getId());
        ProcRuInst procRuInst = ruProcInstMapper.selectOne(queryWrapper);
        DefaultProcInstContext childContext = createSubProcContext(procRuInst);
        StartEventHandler startEventHandler = new StartEventHandler();
        ProcessModel curProcessModel = childContext.getCurProcessModel();
        StartEvent startEvent = curProcessModel.getStartEvent();
        startEventHandler.start(childContext, startEvent.getDefKey());
    }


    private DefaultProcInstContext createSubProcContext(ProcRuInst procRuInst) {
        FlyQiuFlowGlobalContext globalContext = procContext.getGlobalContext();
        ProcessModel process = currentElement;
        DefaultProcInstContext childContext = DefaultProcInstContext.create(procContext);
        childContext.setProcInst(procRuInst);
        childContext.setGlobalContext(globalContext);
        childContext.setCurProcessModel(process);

        return childContext;
    }
}
